package com.itheima.springbootautoconfig;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

/**
 * @author wuhaohua
 */
@SpringBootApplication
public class SpringbootAutoConfigApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(SpringbootAutoConfigApplication.class, args);

		// 如果项目引入了spring-boot-starter-web，Spring就会自动注入一个dispatcherServlet对象
		/**
		 * 通过跟踪代码，发现@SpringBootApplication注解是一个组合注解，其中包含一个@EnableAutoConfiguration组合注解，@EnableAutoConfiguration注解里使用@Import({AutoConfigurationImportSelector.class})导入了AutoConfigurationImportSelector配置类，通过实现ImportSelector接口实现了批量导入配置信息；
		 * AutoConfigurationImportSelector类实现了DeferredImportSelector接口，DeferredImportSelector接口集成自ImportSelector接口，AutoConfigurationImportSelector类实现了selectImports方法，在该方法中，通过调用getAutoConfigurationEntry()方法和getCandidateConfigurations()方法实现自动注入；
		 * 在getCandidateConfigurations()方法中，可以看到一个断言，当configurations为空时，会打印一段提示，提示内写了在META-INF/spring/目录下有一个org.springframework.boot.autoconfigure.AutoConfiguration.imports文件没有被找到；
		 * 通过项目pom文件，跟踪spring-boot-starter依赖，在其中找到spring-boot-autoconfigure依赖，在依赖包中找到spring-boot-autoconfigure的jar包，打开看到其中有META-INF/spring/目录，其下有org.springframework.boot.autoconfigure.AutoConfiguration.imports文件，里面记录了很多需要自动加载的配置文件，其中也包括DispatcherServletAutoConfiguration配置类；
		 * 打开DispatcherServletAutoConfiguration类的代码，可以看到其上有@AutoConfiguration注解（用来标注当前这个类是个自动配置类）和@ConditionalOnClass({DispatcherServlet.class})注解，意思是如果当前环境中有DispatcherServlet这个类，则DispatcherServletAutoConfiguration配置类就生效，也就是自动注入DispatcherServlet的bean对象，具体实现方法是：
		 * 在DispatcherServletAutoConfiguration类内部声明了一个DispatcherServletConfiguration配置类，其有一个方法为dispatcherServlet()方法，这个方法上写了@Bean注解，从而实现了dispatcherServlet的自动注解
		 */
		System.out.println(context.getBean("dispatcherServlet"));

		/**
		 * 构建一个Maven项目demo-autoconfig-pojo，然后编写代码，最后编写DemoConfig配置类、DemoAutoConfig自动配置类，在resources目录下新建META-INF/spring目录，新建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件，并在其中填写DemoAutoConfig自动配置类的全类名，实现自动加载对象；
		 * 通过mvn install命令将demo-autoconfig-pojo项目部署到本地库；
		 * 在本项目中通过pom文件引入demo-autoconfig-pojo，实现了自动加载对象。
		 */
		System.out.println(context.getBean("province"));
		System.out.println(context.getBean("person"));

		/**
		 * 自动配置的原理简述：
		 * 1、在主启动类上添加的SpringBootApplication注解，这个注解组合了EnableAutoConfiguration注解；
		 * 2、EnableAutoConfiguration注解又组合了Import注解，导入了AutoConfigurationImportSelector类；
		 * 3、实现selectImports方法，这个方法经过层层调用，最终会读取META-INF目录下的后缀名为.imports文件（SpringBoot2.7以前的版本读取的是spring.factories文件，2.7至3.0同时支持两个文件，3.0及以后只支持.imports文件）；
		 * 4、读取到全类名之后，会解析注册条件，也就是@Conditional注解及其衍生注解，把满足注册条件的Bean对象自动注入到IOC容器中。
		 */
	}

}
